package com.iteaj.iot.serial;

import com.fazecast.jSerialComm.SerialPort;
import com.iteaj.iot.ProtocolHandle;
import com.iteaj.iot.utils.ByteUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public interface SerialEventProtocolHandle extends ProtocolHandle<SerialEventProtocol> {

    SerialEventProtocolHandle LOGGER_HANDLE = new LoggerSerialProtocolHandle();

    @Override
    default Object handle(SerialEventProtocol protocol) {
        if(protocol.getEvent() != null) {
            int eventType = protocol.getEvent().getEventType();
            switch (eventType) {
                case SerialPort.LISTENING_EVENT_DATA_RECEIVED:
                    readEvent(protocol.getEvent().getReceivedData(), protocol); break;
                case SerialPort.LISTENING_EVENT_DATA_WRITTEN:
                    writeEvent(protocol); break;
                case SerialPort.LISTENING_EVENT_TIMED_OUT:
                    timeoutEvent(protocol); break;
                case SerialPort.LISTENING_EVENT_BREAK_INTERRUPT
                        | SerialPort.LISTENING_EVENT_FRAMING_ERROR
                        | SerialPort.LISTENING_EVENT_PARITY_ERROR
                        | SerialPort.LISTENING_EVENT_FIRMWARE_OVERRUN_ERROR
                        | SerialPort.LISTENING_EVENT_SOFTWARE_OVERRUN_ERROR:
                    errorEvent(protocol); break;
                case SerialPort.LISTENING_EVENT_DSR:
                    dataSetReadyEvent(protocol); break;
                case SerialPort.LISTENING_EVENT_PORT_DISCONNECTED:
                    disconnectedEvent(protocol); break;
                default: otherEvent(eventType, protocol); break;
            }
        } else {
            errorEvent(protocol);
        }
        return null;
    }

    /**
     * 失去连接
     * @param protocol
     */
    default void disconnectedEvent(SerialEventProtocol protocol) { }

    /**
     * 其他事件处理
     * @param eventType <hr>
     *     {@link SerialPort#LISTENING_EVENT_DATA_RECEIVED}
     *     {@link SerialPort#LISTENING_EVENT_DATA_WRITTEN}
     *     {@link SerialPort#LISTENING_EVENT_DATA_AVAILABLE}
     *                  ......
     * @param protocol
     */
    default void otherEvent(int eventType, SerialEventProtocol protocol) { }

    /**
     * 数据读事件
     * @param receivedData 读取的数据
     * @param protocol
     */
    void readEvent(byte[] receivedData, SerialEventProtocol protocol);

    default void writeEvent(SerialEventProtocol protocol) { }

    /**
     * 超时事件
     * @param protocol
     */
    default void timeoutEvent(SerialEventProtocol protocol) { }

    /**
     * 数据准备好事件
     * @param protocol
     */
    default void dataSetReadyEvent(SerialEventProtocol protocol) { }

    /**
     * 中断事件
     * @param protocol
     */
    default void errorEvent(SerialEventProtocol protocol) { }

    class LoggerSerialProtocolHandle implements SerialEventProtocolHandle {

        private Logger logger = LoggerFactory.getLogger(LoggerSerialProtocolHandle.class);

        @Override
        public void readEvent(byte[] receivedData, SerialEventProtocol protocol) {
            this.printLogger(protocol, "接收事件");
        }

        @Override
        public void writeEvent(SerialEventProtocol protocol) {
            this.printLogger(protocol, "写事件");
        }

        @Override
        public void disconnectedEvent(SerialEventProtocol protocol) {
            this.printLogger(protocol, "断开事件");
        }

        @Override
        public void otherEvent(int eventType, SerialEventProtocol protocol) {
            this.printLogger(protocol, eventType+"");
        }

        @Override
        public void timeoutEvent(SerialEventProtocol protocol) {
            this.printLogger(protocol, "超时事件");
        }

        @Override
        public void dataSetReadyEvent(SerialEventProtocol protocol) {
            this.printLogger(protocol, "数据准备好事件");
        }

        @Override
        public void errorEvent(SerialEventProtocol protocol) {
            this.printLogger(protocol, "异常事件");
        }

        /**
         * 打印日志
         * @param protocol
         */
        public void printLogger(SerialEventProtocol protocol, String event) {
            if(logger.isInfoEnabled()) {
                String data = ByteUtil.bytesToHexByFormat(protocol.getEvent().getReceivedData());
                logger.info("串口 监听到事件({}) - 串口: {} - 数据: {}", event, protocol.getConnectProperties(), data);
            }
        }
    }
}
